﻿using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;

namespace Mars.GpuInstance
{
    [Serializable]
    public class GPUAnimationData : ScriptableObject
    {
        public List<GPUAnimationClipData> clipDataList;
        public List<GPUSkinnedMeshData> skinnedMeshDataList;
        public List<GPUBone> bones;
        public Texture2D animTex;
        //public Texture2D animQuaternionTex;
        //public Texture2D animOffsetScaleTex;
        //public Texture2D animAdditionalScaleTex;
        public int totalFrameCount;
        public int totalBoneCount;
        public int textureSizeX;
        public int textureSizeY;
        
        //public List<int> nonPropScaleBoneIndexes;
        //public int nonPropScaleTexSizeX;
        //public int nonPropScaleTexSizeY;
        
        public GPUAnimationData()
        {
            clipDataList = new List<GPUAnimationClipData>();
            skinnedMeshDataList = new List<GPUSkinnedMeshData>();
            bones = new List<GPUBone>();
        }
        
        public GPUBone GetBoneByTransform(string boneTransformName)
        {
            if (bones == null)
            {
                bones = new List<GPUBone>();
            }
            return bones.Find(b => b.boneTransformName == boneTransformName);
        }
        
        public int GetBoneIndexByTransform(string boneTransformName)
        {
            GPUBone bone = GetBoneByTransform(boneTransformName);
            if (bone != null)
            {
                return bone.boneIndex;
            }
            else
            {
                Debug.LogError("[GPUAnimationData] 找不到对应的骨骼节点: " + boneTransformName);
                return -1;
            }
        }
        
        public void BoneSetParent(GPUBone child, GPUBone parent)
        {
            child.parentBoneIndex = parent.boneIndex;
            parent.AddChild(child.boneIndex);
        }

        public GPUSkinnedMeshData GetSkinnedMeshDataByName(string transformName)
        {
            GPUSkinnedMeshData result = null;
            if (skinnedMeshDataList != null && skinnedMeshDataList.Count > 0)
            {
                result = skinnedMeshDataList.Find(smd => smd.transformName.Equals(transformName));
                if (result == null)
                {
                    Debug.LogError("[GPUAnimationData] 节点上找不到蒙皮网格，name = : " + transformName);
                }
            }
            return result;
        }
    }
    
    [Serializable]
    public struct GPUAnimationClipData
    {
        public string clipName;
        public int clipIndex;
        public int clipStartFrame;
        public int clipFrameCount;
        public float length;
        public int isLoopDisabled;
        
        public bool nonPropScaling;
        public int clipNonPropScaleStartFrame;
        public int[] nonPropScaleBoneIndexes;
        public BoneData[] boneDataArr;

        public int animTexDataStartIndex;
        public int animTexNonPropDataStartIndex;
        public int propBoneCount;
        
        public bool IsLoopDisabled()
        {
            return isLoopDisabled > 0;
        }

        public void Clear()
        {
            clipName = "";
            clipIndex = 0;
            clipStartFrame = 0;
            clipFrameCount = 0;
            length = 0;
            isLoopDisabled = 0;
        }

        [Serializable]
        public struct BoneData
        {
            public bool nonPropScaling;
            public int index;
        }
    }
    
    [Serializable]
    public class GPUSkinnedMeshData
    {
        public string transformName;
        public int[] boneIndexes;
        public bool hasBindPoseOffset;
        public Matrix4x4 bindPoseOffset;

        public int GetArrayIndexOfBone(GPUBone bone)
        {
            for (int i = 0; i < boneIndexes.Length; i++)
            {
                if (boneIndexes[i] == bone.boneIndex)
                {
                    return i;
                }
            }
            return -1;
        }
    }
    
    
    [Serializable]
    public class GPUBone
    {
        public string boneTransformName;
        public int boneIndex;
        public int parentBoneIndex;
        public List<int> childBoneIndexes;

        public void AddChild(int childBoneIndex)
        {
            if (childBoneIndexes == null)
            {
                childBoneIndexes = new List<int>();
            }
            if (!childBoneIndexes.Contains(childBoneIndex))
            {
                childBoneIndexes.Add(childBoneIndex);
            }
        }
        public void RemoveChild(int childBoneIndex)
        {
            if (childBoneIndexes != null)
            {
                childBoneIndexes.Remove(childBoneIndex);
            }
        }
    }
    
    [Serializable]
    public struct GPURootMotion
    {
        public int hasMotion;
        public int isPositionOnly;
        public Matrix4x4 motionMatrix;

        public bool HasMotion()
        {
            return hasMotion > 0;
        }
        public bool IsPositionOnly()
        {
            return isPositionOnly > 0;
        }
    }

    [Serializable]
    public class GPUAnimatorState
    {
        public string fullPathName;
        public int hashCode;
        public float cycleOffset;
        public bool isBlend;
    }
    
    public class GPUTransition
    {
        public int arrayIndex { get; private set; }
        public float startTime { get; private set; }
        public float totalTime;
        public int transitioningClipCount { get; private set; }
        public Vector2 startWeights { get; private set; }
        public Vector2 endWeights { get; private set; }
        public int endActiveClipCount { get; private set; }

        public void SetData(int arrayIndex, float startTime, float totalTime, int transitioningClipCount,
            Vector2 startWeights, Vector2 endWeights, int endActiveClipCount)
        {
            this.arrayIndex = arrayIndex;
            this.startTime = startTime;
            this.totalTime = totalTime;
            this.transitioningClipCount = transitioningClipCount;
            this.startWeights = startWeights;
            this.endWeights = endWeights;
            this.endActiveClipCount = endActiveClipCount;
        }

        public void UpdateArrayIndex(int index)
        {
            arrayIndex = index;
        }
    }
    
    [StructLayout(LayoutKind.Sequential)]
    public struct AnchorInfo
    {
        public Vector3 position;
        public Quaternion rotation;
    }
}
